package folder.model.network;

import java.util.List;

import folder.model.link.Link;
import folder.model.node.Node;

public class NetworkRandom
{	
	private static final double DISTANCE_KMS_MIN =  1;
	private static final double DISTANCE_KMS_MAX = 50;
	
	private static final double BANDWIDTH_MIN = 100;
	private static final double BANDWIDTH_MAX = 100;
	
	private Network network;
	
	public static Network networkRandom( int numberNodes, int numberLinks )
	{
		NetworkRandom networkRandom = new NetworkRandom( numberNodes, numberLinks );
		Network network = networkRandom.network;
		
		return network;
	}
	
	public NetworkRandom( int numberNodes, int numberLinks )
	{
		this.network = Network.network();
		
		this.setNodes( numberNodes );
		this.setLinks( numberLinks );
		this.connectNodesThroughLinks();
	}
	
	private void setNodes( int numberNodes )
	{
		for( int i = 0; i < numberNodes; i++ )
			network.addNode( Node.node( i, network ) );
	}
	
	private void setLinks( int numberLinks )
	{
		List< Node > nodes = network.getNodes();
		List< Link > links = network.getLinks();
		int sumIdentifierOfLink = 0;
		
		int identifierOfLink = 0;
		Node nodeA = null;
		Node nodeB = null;
		Link randomLink = null;
		
		for( int i = 0; i < nodes.size() - 1; i++ )
		{
			identifierOfLink = sumIdentifierOfLink++;
			nodeA = nodes.get( i );
			nodeB = nodes.get( i + 1 );
			randomLink = generateRandomLink( identifierOfLink, nodeA, nodeB );
			links.add( randomLink );
		}
		
		identifierOfLink = sumIdentifierOfLink++;
		nodeA = nodes.get( nodes.size() - 1 );
		nodeB = nodes.get( 0 );
		randomLink = generateRandomLink( identifierOfLink, nodeA, nodeB );
		links.add( randomLink );
		
		while( sumIdentifierOfLink < numberLinks )
		{
			int minimumIdentifierOfNode = 0;
			int maximumIdentifierOfNode = nodes.size() - 1;
			
			int randomIdentifierOfNodeA = minimumIdentifierOfNode + (int) ( Math.random() * ( maximumIdentifierOfNode - minimumIdentifierOfNode + 1 ) );
			int randomIdentifierOfNodeb = minimumIdentifierOfNode + (int) ( Math.random() * ( maximumIdentifierOfNode - minimumIdentifierOfNode + 1 ) );
			
			nodeA = nodes.get( randomIdentifierOfNodeA );
			nodeB = nodes.get( randomIdentifierOfNodeb ); 
			
			if( isNewLink( nodeA, nodeB, links ) )
			{
				identifierOfLink = sumIdentifierOfLink++;
				randomLink = generateRandomLink( identifierOfLink, nodeA, nodeB );
				links.add( randomLink );
			}
		}
	}
	
	private Link generateRandomLink( int identifier, Node nodeA, Node nodeB )
	{
		double randomBandwidth     = Math.floor( Math.random() * ( BANDWIDTH_MAX     - BANDWIDTH_MIN     + 1 ) + BANDWIDTH_MIN    );
		double randomDistanceInKm  = Math.floor( Math.random() * ( DISTANCE_KMS_MAX  - DISTANCE_KMS_MIN  + 1 ) + DISTANCE_KMS_MIN );
		//double distance = Math.random() * ( maxDistance - minDistance) + minDistance;
		
		return Link.link( identifier, randomBandwidth, randomDistanceInKm, nodeA, nodeB, network );
	}
	
	private void connectNodesThroughLinks()
	{
		for( Link link: network.getLinks() )
		{
			link.getNodeA().addLink( link );
			link.getNodeB().addLink( link );
		}
	}
	
	private boolean isNewLink( Node nodeA, Node nodeB, List< Link > links )
	{
		if( nodeA.equals( nodeB ) )
			return false;
		else
		{
			for( Link link: links )
				if( ( link.getNodeA().equals( nodeA ) && link.getNodeB().equals( nodeB ) ) || 
					( link.getNodeA().equals( nodeB ) && link.getNodeB().equals( nodeA ) ) )
						return false;
		}
		
		return true;
	}

}
